﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text.RegularExpressions;
using System.Web.Mvc;
using Ams.Extensions;

namespace Ams.Mvc.Bootstrap.Annotations
{
    public class BootstrapModelMetadataProvider : DataAnnotationsModelMetadataProvider
    {
        protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName)
        {
            var a = SetAttributes(attributes, containerType, propertyName);
            var metadata = base.CreateMetadata(a, containerType, modelAccessor, modelType, propertyName);
            return metadata;
        }

        protected bool Missing<T>(Type modelType, string propertyName)
        {
            if (modelType == null) return true;
            var propertyInfo = modelType.GetProperty(propertyName);
            return propertyInfo.Attribute<T>() == null;
        }

        protected bool Matches(string input, string pattern)
        {
            return Regex.IsMatch(input, pattern, RegexOptions.IgnoreCase);
        }

        protected IEnumerable<Attribute> SetAttributes(IEnumerable<Attribute> attributes, Type containerType, string propertyName)
        {
            var a = attributes as IList<Attribute> ?? attributes.ToList();

            if (Missing<DataTypeAttribute>(containerType, propertyName))
            {
                if (propertyName.Matches("description")) a.Add(new DataTypeAttribute(DataType.MultilineText));
                if (propertyName.Matches("phone")) a.Add(new DataTypeAttribute(DataType.PhoneNumber));
                if (propertyName.Matches("email")) a.Add(new DataTypeAttribute(DataType.EmailAddress));
                if (propertyName.Matches("password")) a.Add(new DataTypeAttribute(DataType.Password));
                if (propertyName.Matches("url")) a.Add(new DataTypeAttribute(DataType.Url));
                if (propertyName.Matches("(image|img|thumbnail)url")) a.Add(new DataTypeAttribute(DataType.ImageUrl));
                if (propertyName.Matches("Date$")) a.Add(new DataTypeAttribute(DataType.Date));
                if (propertyName.Matches("time")) a.Add(new DataTypeAttribute(DataType.Time));
                if (propertyName.Matches("timestamp$")) a.Add(new DataTypeAttribute(DataType.DateTime));
                if (propertyName.Matches("(price|money|amount|cost)")
                    && containerType.GetProperty(propertyName).PropertyType == typeof (decimal))
                    a.Add(new DataTypeAttribute(DataType.Currency));
            }

            if (propertyName.Matches("^(zip|postal)") && Missing<DataTypeAttribute>(containerType, propertyName))
            {
                a.Add(new RegularExpressionAttribute(new PostalCodeAttribute().Pattern));
            }

            if (Missing<DisplayAttribute>(containerType, propertyName) &&
                Missing<DisplayNameAttribute>(containerType, propertyName))
            {
                a.Add(new DisplayAttribute {Name = propertyName.Titlize()});
            }

            return a;
        }
    }
}
